﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;

using LanCommunity.ToolStripRenderer;
using System.Threading;

namespace LanCommunity
{
    public partial class MainForm : Form
    {
        #region Enums
        /// <summary>
        /// Dostępne wątki 
        /// </summary>
        private enum ThreadsEnum: int
        {
            UpdateStatusDevices = 0
        }
        #endregion Enums

        #region Zmienne
        /// <summary>
        /// Lista wątków
        /// </summary>
        private Dictionary<ThreadsEnum, Thread> threadsList = null;
        #endregion Zmienne

        public MainForm()
        {
            InitializeComponent();

            //wczytaj konfigurację
            Config.LoadConfig();
            //ustawienia okna - konfiguracja wczytywanie
            this.Bounds = Config.Bounds;
            //lista urządzeń - konfiguracja wczytywania
            foreach (Config.DeviceInfo deviceInfo in Config.Devices)
            {
                AddDevice(deviceInfo.Host, deviceInfo.Description);
            }

            //tworzy listę wątków
            threadsList = new Dictionary<ThreadsEnum, Thread>();
            threadsList.Add(ThreadsEnum.UpdateStatusDevices, new Thread(new ThreadStart(UpdateStatusDevices)));
            
            //ustawienia wątków
            threadsList[ThreadsEnum.UpdateStatusDevices].IsBackground = true;

            //uruchom timer
            timer.Start();

            //domyślny renderer - wygląd natywny
            RendererManager.Active(this);
            devicesListContextMenu.Renderer = RendererManager.Renderer.CurrentRenderer;
            trayContextMenu.Renderer = RendererManager.Renderer.CurrentRenderer;

            //wywołanie zdarzenie Resize tego okna
            this.OnResize(null);
        }

        /// <summary>
        /// Dodaje urządzenie do listy
        /// </summary>
        /// <param name="address">adres IP</param>
        private void AddDevice(string address)
        {
            AddDevice(address, string.Empty);
        }

        /// <summary>
        /// Dodaje urządzenie do listy
        /// </summary>
        /// <param name="address">adres IP</param>
        /// <param name="description">opis</param>
        private void AddDevice(string address, string description)
        {
            ListViewItem item = new ListViewItem();
            //ikonka urządzenia
            item.ImageIndex = 0;

            //dane urządzenia
            item.Text = address; //adres IP
            item.SubItems.Add(description); //opis
            item.SubItems.Add("Czekaj..."); //status
            item.SubItems.Add("Czekaj..."); //ping

            //dodaj do listy tylko wtedy jeżeli urządzenie nie występuje już na liście
            //sprawdza czy występuje na liście
            foreach (ListViewItem lvi in devicesList.Items)
            {
                if (lvi.Text == item.Text)
                {
                    return;
                }
            }
            //dodaje urządzenie do listy
            devicesList.Items.Add(item);
        }

        /// <summary>
        /// Aktualizuje stan urządzeń (Status, Ping)
        /// </summary>
        private void UpdateStatusDevices()
        {
            //pokazanie komunikatu
            tsslStatus.ShowStatusMessage("Sprawdzanie stanu urządzeń...");

            //sprawdź ping
            for (int i = 0; i < devicesList.Items.Count; i++)
            {
                ListViewItem lvi = null;
                this.Invoke(() =>
                {
                    lvi = devicesList.Items[i];
                });

                string ip = lvi.Text;

                Network net = new Network(ip);
                net.SendPing();

                this.Invoke(() =>
                {
                    string statusMessage = string.Empty;
                    switch (net.Status)
                    {
                        case System.Net.NetworkInformation.IPStatus.Success:
                            statusMessage = "Podłączony";
                            break;

                        case System.Net.NetworkInformation.IPStatus.TimedOut:
                            statusMessage = "Przekroczono limit czasu";
                            break;

                        case System.Net.NetworkInformation.IPStatus.DestinationHostUnreachable:
                            statusMessage = "Docelowy host jest nieosiągalny";
                            break;

                        default:
                            statusMessage = net.Status.ToString();
                            break;
                    }
                    lvi.SubItems[2].Text = statusMessage;
                });

                System.Threading.Thread.Sleep(500); //...bo tak chcę!

                this.Invoke(() =>
                {
                    if (net.Status != System.Net.NetworkInformation.IPStatus.Success)
                        lvi.SubItems[3].Text = string.Empty;
                    else
                        lvi.SubItems[3].Text = string.Format("{0} ms", net.Ping.ToString());
                });

                System.Threading.Thread.Sleep(500); //...bo tak chcę! 
            }

            //usunięcie komunikatu
            tsslStatus.ShowStatusMessage(string.Empty);
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            //dostosuj rozmiary kolumn w liście urządzeń
            columnDescription.Width =
                devicesList.Width -
                columnAddress.Width -
                columnStatus.Width -
                columnPing.Width;

            //ukrycie aplikacji w zasobniku systemowym
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();

                //pokaż balonik
                notifyIcon.ShowBalloonTip(3000);
            }
        }

        private void actionQuit_Execute(object sender, EventArgs e)
        {
            this.Close();
        }

        private void actionShowWindow_Execute(object sender, EventArgs e)
        {
            Show();
            this.WindowState = FormWindowState.Normal;
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            //wyłącz timer
            timer.Stop();

            //zakończ wszystkie aktualnie uruchomione wątki
            //TODO: Jakaś lista wątków, albo coś w tym stylu :)
            var enumeratorThreads = threadsList.Values.GetEnumerator();
            while (enumeratorThreads.MoveNext())
            {
                if (enumeratorThreads.Current.IsAlive)
                    enumeratorThreads.Current.Abort();
            }
            
            //rozmiar i pozycja okna - konfiguracja zapisywanie
            Config.Bounds = this.Bounds;
            //lista urządzeń - konfiguracja czysczenie zapisywanie
            Config.Devices.Clear();
            foreach (ListViewItem lvi in devicesList.Items)
            {
                Config.DeviceInfo deviceInfo = new Config.DeviceInfo(lvi.Text, lvi.SubItems[1].Text);
                Config.Devices.Add(deviceInfo);
            }
            //zapisz konfigurację
            Config.SaveConfig();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            //pozycja okna z konfiguracji
            this.Location = Config.Bounds.Location;
        }

        private void actionAddDevice_Execute(object sender, EventArgs e)
        {
            AddDeviceForm addDeviceForm = new AddDeviceForm();
            addDeviceForm.Icon = this.Icon;
            if (addDeviceForm.ShowDialog() == DialogResult.OK)
            {
                //dodaj urządzenie
                AddDevice(addDeviceForm.Host, addDeviceForm.Description);
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            //jeżeli wątek nie jest wykonywany uruchamia go kolejny raz 
            if (!threadsList[ThreadsEnum.UpdateStatusDevices].IsAlive)
            {
                threadsList[ThreadsEnum.UpdateStatusDevices] = new Thread(new ThreadStart(UpdateStatusDevices));
                threadsList[ThreadsEnum.UpdateStatusDevices].Start();
            }
        }

        private void actionAbout_Execute(object sender, EventArgs e)
        {
            using (AboutForm aboutForm = new AboutForm())
            {
                aboutForm.Icon = this.Icon;
                aboutForm.ShowDialog();
            }
        }

        private void actionEditDevice_Execute(object sender, EventArgs e)
        {
            string host = devicesList.SelectedItems[0].SubItems[0].Text;
            string desc = devicesList.SelectedItems[0].SubItems[1].Text;
            int selectIndex = devicesList.SelectedItems[0].Index; //aktualnie zaznaczone urządzenie
            EditDeviceForm editDeviceForm = new EditDeviceForm(host, desc);
            editDeviceForm.Icon = this.Icon;
            if (editDeviceForm.ShowDialog() == DialogResult.OK)
            {
                //aktualizuj opis
                devicesList.Items[selectIndex].SubItems[1].Text = editDeviceForm.Description; 
            }
        }

        private void actionSearchDevices_Execute(object sender, EventArgs e)
        {
            SearchDevicesForm searchDevicesForm = new SearchDevicesForm();
            searchDevicesForm.Icon = this.Icon;
            searchDevicesForm.Show();
        }

        /// <summary>
        /// Aktualizuje akcje menu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateActionsMenu(object sender, CancelEventArgs e)
        {
            if (devicesList.SelectedItems != null)
            {
                //jeżeli zaznaczone jest więcej niż jedno urządzenie w liście
                if (devicesList.SelectedItems.Count > 1)
                {
                    actionAddDevice.Enabled = true;
                    actionEditDevice.Enabled = false;
                    actionTalk.Enabled = false;
                    actionSendFile.Enabled = false;

                    actionDeleteDevices.Enabled = true;
                }
                //jeżeli zaznaczone jest jedno urządzenie w liście
                else if (devicesList.SelectedItems.Count == 1)
                {
                    actionAddDevice.Enabled = true;
                    actionEditDevice.Enabled = true;
                    actionTalk.Enabled = true;
                    actionSendFile.Enabled = true;

                    actionDeleteDevices.Enabled = true;
                }
                //jeżeli nie ma zaznaczonych urządzeń w liście
                else
                {
                    actionAddDevice.Enabled = true;
                    actionEditDevice.Enabled = false;
                    actionTalk.Enabled = false;
                    actionSendFile.Enabled = false;

                    actionDeleteDevices.Enabled = false;
                }
            }
        }

        private void lanToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            //aktualizuj akcje menu
            UpdateActionsMenu(null, null);
        }

        private void actionDeleteDevices_Execute(object sender, EventArgs e)
        {
            string message = (devicesList.SelectedItems.Count > 1) ?
                "Czy napewno chcesz usunąć zaznaczone urządzenia?" :
                "Czy napewno chcesz usunąć zaznaczone urządzenie?";
            //pokaż pytanie
            if (ShowMessageForm.ShowMessage(this.Icon, 
                ShowMessageForm.ShowMessageType.DeleteDevices, 
                "Usuwanie urządzeń...", 
                message) == DialogResult.Yes)
            {
                //usuń zaznaczone urządzenia
                foreach (ListViewItem lvi in devicesList.SelectedItems)
                {
                    lvi.Remove(); //usuń
                }
            }
        }

        private void actionTalk_Execute(object sender, EventArgs e)
        {
            ShowMessageForm.ShowMessage(this.Icon, ShowMessageForm.ShowMessageType.Information, "Informacja", "Work in progress :)");
        }

        private void actionSendFile_Execute(object sender, EventArgs e)
        {
            ShowMessageForm.ShowMessage(this.Icon, ShowMessageForm.ShowMessageType.Information, "Informacja", "Work in progress :)");
        }
    }
}
